'use strict';

/**
 *
 * @param {*} obj - 要写入属性的对象
 * @param {array|object} props - 属性的定义，允许数组和对象两种格式
 * @param {{writable?: boolean, enumerable?:boolean, configurable?:boolean}|null|undefined} defaults - 默认写入对象属性的设置
 * @return {*} obj
 */
module.exports = function (obj, props, defaults = null) {
	if (typeof obj === 'undefined' || obj === null) return obj;

	var type = typeof props,
		keys = [],
		size = 0,
		isAry = Array.isArray(props);

	if (type === 'function') {
		props = props();
		type = typeof props;
	}

	if (type === 'object' && props !== null && !isAry) {
		keys = Object.keys(props);
		size = keys.length;
	} else if (isAry) {
		size = props.length;
	}

	if (size > 0) {
		defaults = defaults || {};
		var writable = !!defaults.writable;
		var enumerable = typeof defaults.enumerable === 'undefined' || defaults.enumerable === null ? true : !!defaults.enumerable;
		var configurable = !!defaults.configurable;
		// var reference = typeof defaults.reference === 'undefined' || defaults.reference === null ? writable : !writable;

		var defintions = {},
			count = 0;

		for (var i = 0; i < size; i++) {
			var item, key, value;
			if (isAry) {
				item = props[i];
				key = item[key];
				value = item.value;
			} else {
				key = keys[i];
				item = props[key];
				if (typeof item === 'undefined' || item === null) {
					value = null;
					item = {};
				} else if (typeof item === 'function') {
					value = null;
					item = {
						get: item
					};
				} else if (typeof item.value === 'undefined') {
					if (typeof item === 'object' && item !== null && !Array.isArray(item)) {
						value = item;
						item = Object.assign({}, item);
						delete value.get;
						delete value.set;
					} else {
						value = item;
						item = {}
					}
				} else {
					value = item.value;
				}
			}

			// key不得为空，未定义，或者空字符
			if (typeof key === 'undefined' || key === null || key === '') continue;

			var defintion = {writable, enumerable, configurable},
				vType = typeof value,
				// isRef = reference,
				getter = false,
				setter = false;

			if (typeof item.get === 'function') getter = item.get;
			if (typeof item.set === 'function') setter = item.set;

			// if (!isAry) {
			// 	value = item;
			// 	vType = typeof value;
			// }
			// if (vType === 'function') {
			// 	getter = value;
			// }

			let setOrGet = !!(getter || setter);

			// ### writable: default false
			if (typeof item.writable !== 'undefined') defintion.writable = !!item.writable;

			// 如果 value 为 null or undefined
			if ((vType === 'undefined' || value === null)) {
				// 只有指定 get 或者 writable = true
				if (defintion.writable === false && !getter) {
					continue;
				}
			}

			// ### wrieable: default true
			// MDN 默认说明是false，这里默认视为true
			if (typeof item.enumerable !== 'undefined') defintion.enumerable = !!item.enumerable;

			// ### configurable: default false
			if (typeof item.configurable !== 'undefined') defintion.configurable = !!item.configurable;

			// ### isRef: default true
			// 引用说明默认视为true，如果将一个对象作为value，存在引用修改的问题
			// if (typeof item.reference !== 'undefined') isRef = !!item.reference; // 引用

			// 如果禁止写入，则不允许引用
			// if (!defintion.writable) isRef = false;

			if (setOrGet) {
				if (getter) defintion.get = getter;
				if (setter) defintion.set = setter;
				delete defintion.writable;
				delete defintion.value;
			} else {
				// 不支持函数的复制
				// @todo 这里有个问题，如果 writable = false 的话，引用也不会生效
				// if (isRef === false && vType === 'object') {
				// 	var basic = Array.isArray(value) ? [] : {};
				// 	defintion.value = Object.assign(basic, value);
				// } else {
				// 	defintion.value = value;
				// }
				defintion.value = value;
			}

			count++;
			defintions[key] = defintion;

			// 统一执行一次，不循环执行多次
			// Object.defineProperty(obj, key, defintion);
			continue;
		}

		if (count > 0) {
			Object.defineProperties(obj, defintions);
		}
	}

	return obj;
};
